home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- * cones.c
- *
- * This module implements the cone primitive.
- * This file was written by Alexander Enzmann. He wrote the code for
- * cones and generously provided us these enhancements.
- *
- * from Persistence of Vision(tm) Ray Tracer
- * Copyright 1996 Persistence of Vision Team
- *---------------------------------------------------------------------------
- * NOTICE: This source code file is provided so that users may experiment
- * with enhancements to POV-Ray and to port the software to platforms other
- * than those supported by the POV-Ray Team. There are strict rules under
- * which you are permitted to use this file. The rules are in the file
- * named POVLEGAL.DOC which should be distributed with this file. If
- * POVLEGAL.DOC is not available or for more info please contact the POV-Ray
- * Team Coordinator by leaving a message in CompuServe's Graphics Developer's
- * Forum. The latest version of POV-Ray may be found there as well.
- *
- * This program is based on the popular DKB raytracer version 2.12.
- * DKBTrace was originally written by David K. Buck.
- * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
- *
- *****************************************************************************/
-
- #include "frame.h"
- #include "povray.h"
- #include "vector.h"
- #include "povproto.h"
- #include "bbox.h"
- #include "cones.h"
- #include "matrices.h"
- #include "objects.h"
-
-
-
- /*****************************************************************************
- * Local preprocessor defines
- ******************************************************************************/
-
- #define Cone_Tolerance 1.0e-6
-
- #define close(x, y) (fabs(x-y) < EPSILON ? 1 : 0)
-
- /* Part of the cone/cylinder hit. [DB 9/94] */
-
- #define BASE_HIT 1
- #define CAP_HIT 2
- #define SIDE_HIT 3
-
-
-
- /*****************************************************************************
- * Local typedefs
- ******************************************************************************/
-
- typedef struct Cone_Intersection_Structure CONE_INT;
-
- struct Cone_Intersection_Structure
- {
- DBL d; /* Distance of intersection point */
- int t; /* Type of intersection: base/cap plane or side */
- };
-
-
-
- /*****************************************************************************
- * Static functions
- ******************************************************************************/
-
- static int intersect_cone PARAMS((RAY *Ray, CONE *Cone, CONE_INT *Depths));
- static void Destroy_Cone PARAMS((OBJECT *Object));
- static int All_Cone_Intersections PARAMS((OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack));
- static int Inside_Cone PARAMS((VECTOR point, OBJECT *Object));
- static void Cone_Normal PARAMS((VECTOR Result, OBJECT *Object, INTERSECTION *Inter));
- static void *Copy_Cone PARAMS((OBJECT *Object));
- static void Translate_Cone PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans));
- static void Rotate_Cone PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans));
- static void Scale_Cone PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans));
- static void Transform_Cone PARAMS((OBJECT *Object, TRANSFORM *Trans));
- static void Invert_Cone PARAMS((OBJECT *Object));
-
-
- /*****************************************************************************
- * Local variables
- ******************************************************************************/
-
- static METHODS Cone_Methods =
- {
- All_Cone_Intersections,
- Inside_Cone, Cone_Normal,
- Copy_Cone, Translate_Cone, Rotate_Cone, Scale_Cone, Transform_Cone,
- Invert_Cone, Destroy_Cone
- };
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * All_Cone_Intersections
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static int All_Cone_Intersections(Object, Ray, Depth_Stack)
- OBJECT *Object;
- RAY *Ray;
- ISTACK *Depth_Stack;
- {
- int Intersection_Found, cnt, i;
- VECTOR IPoint;
- CONE_INT I[4];
-
- Intersection_Found = FALSE;
-
- if ((cnt = intersect_cone(Ray, (CONE *)Object, I)) != 0)
- {
- for (i = 0; i < cnt; i++)
- {
- VEvaluateRay(IPoint, Ray->Initial, I[i].d, Ray->Direction);
-
- if (Point_In_Clip(IPoint, Object->Clip))
- {
- push_entry_i1(I[i].d,IPoint,Object,I[i].t,Depth_Stack);
-
- Intersection_Found = TRUE;
- }
- }
- }
-
- return (Intersection_Found);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * intersect_cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static int intersect_cone(Ray, Cone, Intersection)
- RAY *Ray;
- CONE *Cone;
- CONE_INT *Intersection;
- {
- int i = 0;
- DBL rdiv;
- DBL a, b, c, z, t1, t2, len;
- DBL d;
- VECTOR P, D;
-
- Increase_Counter(stats[Ray_Cone_Tests]);
-
- /* Transform the ray into the cones space */
-
- MInvTransPoint(P, Ray->Initial, Cone->Trans);
- MInvTransDirection(D, Ray->Direction, Cone->Trans);
-
- VLength(len, D);
- VInverseScaleEq(D, len);
-
- if (Test_Flag(Cone, CYLINDER_FLAG))
- {
- /* Solve intersections with a cylinder */
-
- a = D[X] * D[X] + D[Y] * D[Y];
-
- if (a > EPSILON)
- {
- b = P[X] * D[X] + P[Y] * D[Y];
-
- c = P[X] * P[X] + P[Y] * P[Y] - 1.0;
-
- d = b * b - a * c;
-
- if (d >= 0.0)
- {
- d = sqrt(d);
-
- /*
- t1 = (-b + d) / a;
- t2 = (-b - d) / a;
- */
- rdiv = (1.0 / a);
- t1 = (-b + d) * rdiv;
- t2 = (-b - d) * rdiv;
-
- z = P[Z] + t1 * D[Z];
-
- if ((t1 > Cone_Tolerance) && (t1 < Max_Distance) && (z >= 0.0) && (z <= 1.0))
- {
- Intersection[i].d = t1 / len;
- Intersection[i++].t = SIDE_HIT;
- }
-
- z = P[Z] + t2 * D[Z];
-
- if ((t2 > Cone_Tolerance) && (t1 < Max_Distance) && (z >= 0.0) && (z <= 1.0))
- {
- Intersection[i].d = t2 / len;
- Intersection[i++].t = SIDE_HIT;
- }
- }
- }
- }
- else
- {
- /* Solve intersections with a cone */
-
- a = D[X] * D[X] + D[Y] * D[Y] - D[Z] * D[Z];
-
- b = D[X] * P[X] + D[Y] * P[Y] - D[Z] * P[Z];
-
- c = P[X] * P[X] + P[Y] * P[Y] - P[Z] * P[Z];
-
- if (fabs(a) < EPSILON)
- {
- if (fabs(b) > EPSILON)
- {
- /* One intersection */
-
- t1 = -0.5 * c / b;
-
- z = P[Z] + t1 * D[Z];
-
- if ((t1 > Cone_Tolerance) && (t1 < Max_Distance) && (z >= Cone->dist) && (z <= 1.0))
- {
- Intersection[i].d = t1 / len;
- Intersection[i++].t = SIDE_HIT;
- }
- }
- }
- else
- {
- /* Check hits against the side of the cone */
-
- d = b * b - a * c;
-
- if (d >= 0.0)
- {
- d = sqrt(d);
-
- rdiv = (1.0 / a);
- t1 = (-b - d) * rdiv;
- t2 = (-b + d) * rdiv;
-
- /*
- t1 = (-b - d) / a;
- t2 = (-b + d) / a;
- */
-
- z = P[Z] + t1 * D[Z];
-
- if ((t1 > Cone_Tolerance) && (t1 < Max_Distance) && (z >= Cone->dist) && (z <= 1.0))
- {
- Intersection[i].d = t1 / len;
- Intersection[i++].t = SIDE_HIT;
- }
-
- z = P[Z] + t2 * D[Z];
-
- if ((t2 > Cone_Tolerance) && (t1 < Max_Distance) && (z >= Cone->dist) && (z <= 1.0))
- {
- Intersection[i].d = t2 / len;
- Intersection[i++].t = SIDE_HIT;
- }
- }
- }
- }
-
- if (Test_Flag(Cone, CLOSED_FLAG) && (fabs(D[Z]) > EPSILON))
- {
- d = (1.0 - P[Z]) / D[Z];
-
- a = (P[X] + d * D[X]);
-
- b = (P[Y] + d * D[Y]);
-
- if (((Sqr(a) + Sqr(b)) <= 1.0) && (d > Cone_Tolerance) && (d < Max_Distance))
- {
- Intersection[i].d = d / len;
- Intersection[i++].t = CAP_HIT;
- }
-
- d = (Cone->dist - P[Z]) / D[Z];
-
- a = (P[X] + d * D[X]);
-
- b = (P[Y] + d * D[Y]);
-
- if ((Sqr(a) + Sqr(b)) <= (Test_Flag(Cone, CYLINDER_FLAG) ? 1.0 : Sqr(Cone->dist))
- && (d > Cone_Tolerance) && (d < Max_Distance))
- {
- Intersection[i].d = d / len;
- Intersection[i++].t = BASE_HIT;
- }
- }
-
- if (i)
- {
- Increase_Counter(stats[Ray_Cone_Tests_Succeeded]);
- }
-
- return (i);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Inside_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static int Inside_Cone(IPoint, Object)
- VECTOR IPoint;
- OBJECT *Object;
- {
- CONE *Cone = (CONE *)Object;
- DBL w2, z2, offset = (Test_Flag(Cone, CLOSED_FLAG) ? -EPSILON : EPSILON);
- VECTOR New_Point;
-
- /* Transform the point into the cones space */
-
- MInvTransPoint(New_Point, IPoint, Cone->Trans);
-
- /* Test to see if we are inside the cone */
-
- w2 = New_Point[X] * New_Point[X] + New_Point[Y] * New_Point[Y];
-
- if (Test_Flag(Cone, CYLINDER_FLAG))
- {
- /* Check to see if we are inside a cylinder */
-
- if ((w2 > 1.0 + offset) ||
- (New_Point[Z] < 0.0 - offset) ||
- (New_Point[Z] > 1.0 + offset))
- {
- return (Test_Flag(Cone, INVERTED_FLAG));
- }
- else
- {
- return (!Test_Flag(Cone, INVERTED_FLAG));
- }
- }
- else
- {
- /* Check to see if we are inside a cone */
-
- z2 = New_Point[Z] * New_Point[Z];
-
- if ((w2 > z2 + offset) ||
- (New_Point[Z] < Cone->dist - offset) ||
- (New_Point[Z] > 1.0+offset))
- {
- return (Test_Flag(Cone, INVERTED_FLAG));
- }
- else
- {
- return (!Test_Flag(Cone, INVERTED_FLAG));
- }
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Cone_Normal
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Cone_Normal(Result, Object, Inter)
- OBJECT *Object;
- VECTOR Result;
- INTERSECTION *Inter;
- {
- CONE *Cone = (CONE *)Object;
-
- /* Transform the point into the cones space */
-
- MInvTransPoint(Result, Inter->IPoint, Cone->Trans);
-
- /* Calculating the normal is real simple in canonical cone space */
-
- switch (Inter->i1)
- {
- case SIDE_HIT:
-
- if (Test_Flag(Cone, CYLINDER_FLAG))
- {
- Result[Z] = 0.0;
- }
- else
- {
- Result[Z] = -Result[Z];
- }
-
- break;
-
- case BASE_HIT:
-
- Make_Vector(Result, 0.0, 0.0, -1.0)
-
- break;
-
- case CAP_HIT:
-
- Make_Vector(Result, 0.0, 0.0, 1.0)
-
- break;
- }
-
- /* Transform the point out of the cones space */
-
- MTransNormal(Result, Result, Cone->Trans);
-
- VNormalize(Result, Result);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Translate_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Translate_Cone(Object, Vector, Trans)
- OBJECT *Object;
- VECTOR Vector;
- TRANSFORM *Trans;
- {
- Transform_Cone(Object, Trans);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Rotate_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Rotate_Cone(Object, Vector, Trans)
- OBJECT *Object;
- VECTOR Vector;
- TRANSFORM *Trans;
- {
- Transform_Cone(Object, Trans);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Scale_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Scale_Cone(Object, Vector, Trans)
- OBJECT *Object;
- VECTOR Vector;
- TRANSFORM *Trans;
- {
- Transform_Cone(Object, Trans);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Transform_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Transform_Cone(Object, Trans)
- OBJECT *Object;
- TRANSFORM *Trans;
- {
- CONE *Cone = (CONE *)Object;
-
- Compose_Transforms(Cone->Trans, Trans);
-
- Compute_Cone_BBox(Cone);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Invert_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Invert_Cone(Object)
- OBJECT *Object;
- {
- Invert_Flag(Object, INVERTED_FLAG);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Create_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- CONE *Create_Cone()
- {
- CONE *New;
-
- New = (CONE *)POV_MALLOC(sizeof(CONE), "cone");
-
- INIT_OBJECT_FIELDS(New, CONE_OBJECT, &Cone_Methods)
-
- Make_Vector(New->apex, 0.0, 0.0, 1.0);
- Make_Vector(New->base, 0.0, 0.0, 0.0);
-
- New->apex_radius = 1.0;
- New->base_radius = 0.0;
-
- New->dist = 0.0;
-
- New->Trans = Create_Transform();
-
- /* Cone/Cylinder has capped ends by default. */
-
- Set_Flag(New, CLOSED_FLAG);
-
- /* Default bounds */
-
- Make_BBox(New->BBox, -1.0, -1.0, 0.0, 2.0, 2.0, 1.0);
-
- return (New);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Copy_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void *Copy_Cone(Object)
- OBJECT *Object;
- {
- CONE *New;
-
- New = Create_Cone();
-
- /* Get rid of the transformation created in Create_Cone(). */
-
- Destroy_Transform(New->Trans);
-
- /* Copy cone. */
-
- *New = *((CONE *)Object);
-
- New->Trans = Copy_Transform(((CONE *)Object)->Trans);
-
- return (New);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Create_Cylinder
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- CONE *Create_Cylinder()
- {
- CONE *New;
-
- New = (CONE *)POV_MALLOC(sizeof(CONE), "cone");
-
- INIT_OBJECT_FIELDS(New, CONE_OBJECT, &Cone_Methods)
-
- Make_Vector(New->apex, 0.0, 0.0, 1.0);
- Make_Vector(New->base, 0.0, 0.0, 0.0);
-
- New->apex_radius = 1.0;
- New->base_radius = 1.0;
- New->dist = 0.0;
-
- New->Trans = Create_Transform();
-
- Set_Flag(New, CYLINDER_FLAG); /* This is a cylinder. */
- Set_Flag(New, CLOSED_FLAG); /* Has capped ends. */
-
- /* Default bounds */
-
- Make_BBox(New->BBox, -1.0, -1.0, 0.0, 2.0, 2.0, 1.0);
-
- return (New);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Compute_Cone_Data
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Feb 1996: check for equal sized ends (cylinder) first [AED]
- *
- ******************************************************************************/
-
- void Compute_Cone_Data(Object)
- OBJECT *Object;
- {
- DBL tlen, len, tmpf;
- VECTOR tmpv, axis, origin;
- CONE *Cone = (CONE *)Object;
-
- /* Process the primitive specific information */
-
- if (fabs(Cone->apex_radius - Cone->base_radius) < EPSILON)
- {
- /* What we are dealing with here is really a cylinder */
-
- Set_Flag(Cone, CYLINDER_FLAG);
-
- Compute_Cylinder_Data(Object);
-
- return;
- }
-
- if (Cone->apex_radius < Cone->base_radius)
- {
- /* Want the bigger end at the top */
-
- Assign_Vector(tmpv,Cone->base);
- Assign_Vector(Cone->base,Cone->apex);
- Assign_Vector(Cone->apex,tmpv);
-
- tmpf = Cone->base_radius;
- Cone->base_radius = Cone->apex_radius;
- Cone->apex_radius = tmpf;
- }
-
- /* Find the axis and axis length */
-
- VSub(axis, Cone->apex, Cone->base);
-
- VLength(len, axis);
-
- if (len < EPSILON)
- {
- Error("Degenerate cone/cylinder.\n");
- }
- else
- {
- VInverseScaleEq(axis, len)
- }
-
- /* Determine alignment */
-
- tmpf = Cone->base_radius * len / (Cone->apex_radius - Cone->base_radius);
-
- VScale(origin, axis, tmpf);
-
- VSub(origin, Cone->base, origin);
-
- tlen = tmpf + len;
-
- Cone->dist = tmpf / tlen;
-
- Compute_Coordinate_Transform(Cone->Trans, origin, axis, Cone->apex_radius, tlen);
-
- /* Recalculate the bounds */
-
- Compute_Cone_BBox(Cone);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Compute_Cylinder_Data
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- void Compute_Cylinder_Data(Object)
- OBJECT *Object;
- {
- DBL tmpf;
- VECTOR axis;
- CONE *Cone = (CONE *)Object;
-
- VSub(axis, Cone->apex, Cone->base);
-
- VLength(tmpf, axis);
-
- if (tmpf < EPSILON)
- {
- Error("Degenerate cylinder, base point = apex point.\n");
- }
- else
- {
- VInverseScaleEq(axis, tmpf)
-
- Compute_Coordinate_Transform(Cone->Trans, Cone->base, axis, Cone->apex_radius, tmpf);
- }
-
- Cone->dist = 0.0;
-
- /* Recalculate the bounds */
-
- Compute_Cone_BBox(Cone);
- }
-
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Destroy_Cone
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Destroy_Cone(Object)
- OBJECT *Object;
- {
- Destroy_Transform(((CONE *)Object)->Trans);
-
- POV_FREE (Object);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Compute_Cone_BBox
- *
- * INPUT
- *
- * Cone - Cone/Cylinder
- *
- * OUTPUT
- *
- * Cone
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Calculate the bounding box of a cone or cylinder.
- *
- * CHANGES
- *
- * Aug 1994 : Creation.
- *
- ******************************************************************************/
-
- void Compute_Cone_BBox(Cone)
- CONE *Cone;
- {
- Make_BBox(Cone->BBox, -1.0, -1.0, 0.0, 2.0, 2.0, 1.0);
-
- Recompute_BBox(&Cone->BBox, Cone->Trans);
- }
-
-